#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
登录模块
提供登录功能和会话管理，供其他模块调用
"""

import time
import json
import os
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import TimeoutException, NoSuchElementException
from datetime import datetime, timedelta

class LoginManager:
    def __init__(self, headless=False):
        """
        初始化登录管理器
        
        Args:
            headless (bool): 是否使用无头模式
        """
        self.base_url = "https://om0813.zw7gmc49.work"
        self.login_url = f"{self.base_url}/login"  # 假设登录页面路径
        self.driver = None
        self.headless = headless
        self.is_logged_in = False
        self.session_file = "downloads/session.json"
        self.cookies_file = "downloads/cookies.json"
        
    def setup_driver(self):
        """设置Chrome浏览器驱动"""
        try:
            # 使用标准selenium Chrome驱动
            options = Options()
            options.add_argument('--no-sandbox')
            options.add_argument('--disable-dev-shm-usage')
            options.add_argument('--disable-blink-features=AutomationControlled')
            options.add_experimental_option("excludeSwitches", ["enable-automation"])
            options.add_experimental_option('useAutomationExtension', False)
            options.add_argument('--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')
            
            if self.headless:
                options.add_argument('--headless')
                options.add_argument('--disable-gpu')
                options.add_argument('--window-size=1920,1080')
            
            self.driver = webdriver.Chrome(options=options)
            
            # 执行脚本来隐藏webdriver属性
            self.driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
            
            print("浏览器驱动设置成功")
            return True
            
        except Exception as e:
            print(f"设置浏览器驱动失败: {e}")
            return False
    
    def check_login_status(self):
        """检查当前登录状态"""
        try:
            # 访问主页检查是否有登录标识
            self.driver.get(self.base_url)
            time.sleep(3)
            
            # 查找登录状态的标识元素
            login_indicators = [
                "//a[contains(text(), '登录')]",
                "//a[contains(text(), 'Login')]",
                "//button[contains(text(), '登录')]",
                "//div[contains(@class, 'login')]",
                "//span[contains(text(), '登录')]"
            ]
            
            # 查找用户信息的标识元素
            user_indicators = [
                "//a[contains(text(), '用户')]",
                "//a[contains(text(), 'User')]",
                "//div[contains(@class, 'user')]",
                "//span[contains(text(), '用户')]",
                "//div[contains(@class, 'avatar')]",
                "//img[contains(@class, 'avatar')]"
            ]
            
            # 检查是否有登录按钮
            has_login_button = False
            for indicator in login_indicators:
                try:
                    elements = self.driver.find_elements(By.XPATH, indicator)
                    if elements:
                        has_login_button = True
                        break
                except:
                    continue
            
            # 检查是否有用户信息
            has_user_info = False
            for indicator in user_indicators:
                try:
                    elements = self.driver.find_elements(By.XPATH, indicator)
                    if elements:
                        has_user_info = True
                        break
                except:
                    continue
            
            # 判断登录状态
            if has_user_info and not has_login_button:
                self.is_logged_in = True
                print("检测到已登录状态")
                return True
            else:
                self.is_logged_in = False
                print("检测到未登录状态")
                return False
                
        except Exception as e:
            print(f"检查登录状态时出错: {e}")
            return False
    
    def find_login_elements(self):
        """查找登录页面元素"""
        try:
            # 等待页面加载
            time.sleep(3)
            
            # 查找用户名输入框
            username_selectors = [
                "//input[@name='username']",
                "//input[@name='user']",
                "//input[@name='email']",
                "//input[@type='text']",
                "//input[@placeholder*='用户名']",
                "//input[@placeholder*='用户']",
                "//input[@placeholder*='账号']",
                "//input[@placeholder*='email']",
                "//input[@placeholder*='Email']"
            ]
            
            username_input = None
            for selector in username_selectors:
                try:
                    elements = self.driver.find_elements(By.XPATH, selector)
                    if elements:
                        username_input = elements[0]
                        print(f"找到用户名输入框: {selector}")
                        break
                except:
                    continue
            
            # 查找密码输入框
            password_selectors = [
                "//input[@name='password']",
                "//input[@name='pass']",
                "//input[@name='pwd']",
                "//input[@type='password']",
                "//input[@placeholder*='密码']",
                "//input[@placeholder*='Password']"
            ]
            
            password_input = None
            for selector in password_selectors:
                try:
                    elements = self.driver.find_elements(By.XPATH, selector)
                    if elements:
                        password_input = elements[0]
                        print(f"找到密码输入框: {selector}")
                        break
                except:
                    continue
            
            # 查找登录按钮
            login_button_selectors = [
                "//div[@class='item' and contains(text(), '登录')]",  # 特定的登录按钮结构
                "//div[contains(@class, 'item') and contains(text(), '登录')]",
                "//button[@type='submit']",
                "//button[contains(text(), '登录')]",
                "//button[contains(text(), 'Login')]",
                "//button[contains(text(), '登入')]",
                "//button[contains(text(), 'Sign in')]",
                "//input[@type='submit']",
                "//input[@value*='登录']",
                "//input[@value*='Login']",
                "//a[contains(text(), '登录')]",
                "//a[contains(text(), 'Login')]",
                "//div[contains(@class, 'login-btn')]",
                "//div[contains(@class, 'submit')]",
                "//span[contains(text(), '登录')]",
                "//span[contains(text(), 'Login')]",
                "//div[contains(@class, 'btn')]",
                "//div[contains(@class, 'button')]",
                "//*[contains(@class, 'submit')]",
                "//*[contains(@class, 'login')]"
            ]
            
            login_button = None
            for selector in login_button_selectors:
                try:
                    elements = self.driver.find_elements(By.XPATH, selector)
                    if elements:
                        login_button = elements[0]
                        print(f"找到登录按钮: {selector}")
                        break
                except:
                    continue
            
            return username_input, password_input, login_button
            
        except Exception as e:
            print(f"查找登录元素时出错: {e}")
            return None, None, None
    
    def manual_login(self, username, password):
        """
        手动登录
        
        Args:
            username (str): 用户名
            password (str): 密码
        """
        try:
            print("开始手动登录...")
            
            # 访问登录页面
            self.driver.get(self.login_url)
            print("登录页面已加载，正在处理广告...")
            
            # 等待并自动关闭弹窗广告
            self.wait_for_ads_to_disappear()
            
            # 查找登录元素
            username_input, password_input, login_button = self.find_login_elements()
            
            if not username_input or not password_input or not login_button:
                print("未找到登录元素，请检查页面结构")
                # 保存页面源码用于分析
                self.save_page_source("login_page_source.html")
                return False
            
            # 输入用户名和密码
            username_input.clear()
            username_input.send_keys(username)
            time.sleep(1)
            
            password_input.clear()
            password_input.send_keys(password)
            time.sleep(1)
            
            # 点击登录按钮
            print("正在点击登录按钮...")
            try:
                login_button.click()
                print("登录按钮已点击，等待响应...")
                time.sleep(8)  # 增加等待时间
                
                # 检查登录结果
                print("正在检查登录状态...")
                if self.check_login_status():
                    print("登录成功！")
                    self.save_session()
                    return True
                else:
                    print("登录失败，请检查用户名和密码")
                    return False
            except Exception as e:
                print(f"点击登录按钮时出错: {e}")
                # 保存当前页面状态
                self.save_page_source("login_error_page.html")
                return False
                
        except Exception as e:
            print(f"手动登录时出错: {e}")
            return False
    
    def auto_login(self):
        """自动登录（使用保存的会话）"""
        try:
            print("尝试自动登录...")
            
            # 检查是否有保存的会话
            if not os.path.exists(self.session_file):
                print("没有找到保存的会话文件")
                return False
            
            # 加载会话信息
            with open(self.session_file, 'r', encoding='utf-8') as f:
                session_data = json.load(f)
            
            # 检查会话是否过期
            if 'expires_at' in session_data:
                expires_at = datetime.fromisoformat(session_data['expires_at'])
                if datetime.now() > expires_at:
                    print("会话已过期")
                    return False
            
            # 设置cookies
            if os.path.exists(self.cookies_file):
                with open(self.cookies_file, 'r', encoding='utf-8') as f:
                    cookies = json.load(f)
                
                # 先访问网站，然后设置cookies
                self.driver.get(self.base_url)
                time.sleep(2)
                
                for cookie in cookies:
                    try:
                        self.driver.add_cookie(cookie)
                    except:
                        continue
                
                # 刷新页面
                self.driver.refresh()
                time.sleep(3)
                
                # 检查登录状态
                if self.check_login_status():
                    print("自动登录成功！")
                    return True
                else:
                    print("自动登录失败")
                    return False
            
            return False
            
        except Exception as e:
            print(f"自动登录时出错: {e}")
            return False
    
    def save_session(self):
        """保存会话信息"""
        try:
            # 确保downloads目录存在
            os.makedirs('downloads', exist_ok=True)
            
            # 保存cookies
            cookies = self.driver.get_cookies()
            with open(self.cookies_file, 'w', encoding='utf-8') as f:
                json.dump(cookies, f, ensure_ascii=False, indent=2)
            
            # 保存会话信息
            session_data = {
                'logged_in': True,
                'login_time': datetime.now().isoformat(),
                'expires_at': (datetime.now() + timedelta(hours=24)).isoformat(),  # 24小时后过期
                'user_agent': self.driver.execute_script("return navigator.userAgent;")
            }
            
            with open(self.session_file, 'w', encoding='utf-8') as f:
                json.dump(session_data, f, ensure_ascii=False, indent=2)
            
            print("会话信息已保存")
            
        except Exception as e:
            print(f"保存会话信息时出错: {e}")
    
    def clear_session(self):
        """清除会话信息"""
        try:
            if os.path.exists(self.session_file):
                os.remove(self.session_file)
                print("会话文件已删除")
            
            if os.path.exists(self.cookies_file):
                os.remove(self.cookies_file)
                print("Cookies文件已删除")
            
            self.is_logged_in = False
            
        except Exception as e:
            print(f"清除会话信息时出错: {e}")
    
    def save_page_source(self, filename):
        """保存页面源码用于分析"""
        try:
            # 确保downloads目录存在
            os.makedirs('downloads', exist_ok=True)
            filepath = os.path.join('downloads', filename)
            
            page_source = self.driver.page_source
            with open(filepath, 'w', encoding='utf-8') as f:
                f.write(page_source)
            
            print(f"页面源码已保存到: {filepath}")
            
            # 同时保存截图
            screenshot_file = filename.replace('.html', '.png')
            screenshot_path = os.path.join('downloads', screenshot_file)
            self.driver.save_screenshot(screenshot_path)
            print(f"页面截图已保存到: {screenshot_path}")
            
        except Exception as e:
            print(f"保存页面源码时出错: {e}")
    
    def close_popup_ads(self):
        """自动关闭弹窗广告"""
        try:
            print("正在尝试关闭弹窗广告...")
            
            # 优先选择关闭按钮，避免点击广告内容
            close_selectors = [
                # Vant UI 框架的关闭图标（优先级最高）
                "//i[contains(@class, 'van-icon-close')]",
                "//i[contains(@class, 'van-icon') and contains(@class, 'close')]",
                "//*[contains(@class, 'van-icon-close')]",
                # 明确的关闭按钮选择器
                "//div[contains(@class, 'close') and not(contains(@class, 'ad'))]",
                "//span[contains(@class, 'close') and not(contains(@class, 'ad'))]",
                "//i[contains(@class, 'close') and not(contains(@class, 'ad'))]",
                "//button[contains(@class, 'close') and not(contains(@class, 'ad'))]",
                "//a[contains(@class, 'close') and not(contains(@class, 'ad'))]",
                # 弹窗内的关闭按钮
                "//div[contains(@class, 'popup')]//div[contains(@class, 'close')]",
                "//div[contains(@class, 'modal')]//div[contains(@class, 'close')]",
                "//div[contains(@class, 'overlay')]//div[contains(@class, 'close')]",
                "//div[contains(@class, 'dialog')]//div[contains(@class, 'close')]",
                # 明确的关闭文字按钮
                "//*[contains(text(), '×') and not(contains(@class, 'ad'))]",
                "//*[contains(text(), 'X') and not(contains(@class, 'ad'))]",
                "//*[contains(text(), '关闭') and not(contains(@class, 'ad'))]",
                "//*[contains(text(), 'Close') and not(contains(@class, 'ad'))]",
                # 其他可能的关闭按钮
                "//*[contains(@class, 'close-btn')]",
                "//*[contains(@class, 'close-button')]",
                "//*[contains(@class, 'close') and contains(@class, 'btn')]",
                "//*[contains(@class, 'close') and contains(@class, 'button')]",
                "//*[contains(@class, 'close') and contains(@class, 'icon')]",
                "//*[contains(@class, 'close') and contains(@class, 'exit')]"
            ]
            
            ads_closed = 0
            max_attempts = 5  # 最大尝试次数
            
            for attempt in range(max_attempts):
                print(f"第 {attempt + 1} 轮弹窗检测...")
                round_closed = 0
                
                # 检查窗口状态
                try:
                    current_window = self.driver.current_window_handle
                    if not current_window:
                        print("浏览器窗口已关闭，停止弹窗处理")
                        break
                except:
                    print("无法获取当前窗口，停止弹窗处理")
                    break
                
                for selector in close_selectors:
                    try:
                        elements = self.driver.find_elements(By.XPATH, selector)
                        for element in elements:
                            try:
                                # 再次检查窗口状态
                                if not self.driver.current_window_handle:
                                    print("浏览器窗口已关闭，停止处理")
                                    return ads_closed
                                
                                if element.is_displayed() and element.is_enabled():
                                    print(f"找到可点击元素: {selector}")
                                    
                                    # 检查元素是否在广告区域内
                                    if self.is_ad_element(element):
                                        print("跳过广告元素，寻找真正的关闭按钮")
                                        continue
                                    
                                    # 尝试点击
                                    element.click()
                                    time.sleep(0.5)
                                    round_closed += 1
                                    print(f"已关闭第 {round_closed} 个弹窗")
                                    
                                    # 如果这个元素是弹窗本身，尝试查找其内部的关闭按钮
                                    if any(keyword in selector.lower() for keyword in ['popup', 'modal', 'overlay', 'dialog']):
                                        self.close_nested_popup_ads(element)
                                        
                            except Exception as e:
                                print(f"点击元素时出错: {e}")
                                continue
                    except Exception as e:
                        continue
                
                if round_closed == 0:
                    print(f"第 {attempt + 1} 轮未发现新弹窗")
                    break
                
                ads_closed += round_closed
                time.sleep(1)  # 等待新弹窗出现
            
            if ads_closed > 0:
                print(f"总共关闭 {ads_closed} 个弹窗广告")
            else:
                print("未找到弹窗广告或关闭按钮")
            
            return ads_closed
                
        except Exception as e:
            print(f"关闭弹窗广告时出错: {e}")
            return 0
    
    def close_nested_popup_ads(self, parent_element):
        """关闭嵌套在弹窗内的广告"""
        try:
            nested_selectors = [
                ".//div[contains(@class, 'close')]",
                ".//span[contains(@class, 'close')]",
                ".//i[contains(@class, 'close')]",
                ".//button[contains(@class, 'close')]",
                ".//a[contains(@class, 'close')]",
                ".//*[contains(text(), '关闭')]",
                ".//*[contains(text(), 'Close')]",
                ".//*[contains(text(), '×')]",
                ".//*[contains(text(), 'X')]"
            ]
            
            for selector in nested_selectors:
                try:
                    close_btn = parent_element.find_element(By.XPATH, selector)
                    if close_btn.is_displayed() and close_btn.is_enabled():
                        close_btn.click()
                        time.sleep(0.3)
                        print("关闭嵌套弹窗")
                        break
                except:
                    continue
                    
        except Exception as e:
            print(f"关闭嵌套弹窗时出错: {e}")
    
    def is_ad_element(self, element):
        """检查元素是否为广告元素"""
        try:
            # 检查元素的class是否包含广告相关词汇
            class_attr = element.get_attribute("class") or ""
            if any(keyword in class_attr.lower() for keyword in ['ad', 'banner', 'sponsor', 'promotion']):
                return True
            
            # 检查元素的文本内容
            text = element.text or ""
            if any(keyword in text.lower() for keyword in ['广告', 'ad', 'banner', 'sponsor', 'promotion']):
                return True
            
            # 检查元素的父级是否包含广告相关词汇
            try:
                parent = element.find_element(By.XPATH, "./..")
                parent_class = parent.get_attribute("class") or ""
                if any(keyword in parent_class.lower() for keyword in ['ad', 'banner', 'sponsor', 'promotion']):
                    return True
            except:
                pass
            
            return False
            
        except Exception as e:
            print(f"检查广告元素时出错: {e}")
            return False
    
    def wait_for_ads_to_disappear(self, max_wait_time=20):
        """等待广告消失"""
        try:
            print("等待广告消失...")
            start_time = time.time()
            last_ads_count = 0
            
            while time.time() - start_time < max_wait_time:
                # 尝试关闭弹窗广告
                current_ads_closed = self.close_popup_ads()
                
                # 检查是否还有明显的广告元素
                ad_indicators = [
                    "//div[contains(@class, 'ad')]",
                    "//div[contains(@class, 'banner')]",
                    "//div[contains(@class, 'popup')]",
                    "//div[contains(@class, 'modal')]",
                    "//div[contains(@class, 'overlay')]",
                    "//div[contains(@class, 'notification')]",
                    "//div[contains(@class, 'alert')]",
                    "//div[contains(@class, 'toast')]",
                    "//div[contains(@class, 'message')]",
                    "//div[contains(@class, 'dialog')]"
                ]
                
                current_ads_count = 0
                for indicator in ad_indicators:
                    try:
                        elements = self.driver.find_elements(By.XPATH, indicator)
                        for elem in elements:
                            if elem.is_displayed():
                                current_ads_count += 1
                    except:
                        continue
                
                print(f"当前检测到 {current_ads_count} 个广告元素")
                
                # 如果连续两轮都没有新弹窗，认为广告已处理完毕
                if current_ads_count == 0:
                    print("未检测到广告元素，继续执行...")
                    return True
                
                # 如果广告数量没有减少，可能还有新弹窗出现
                if current_ads_count >= last_ads_count:
                    print("广告数量未减少，继续处理...")
                    time.sleep(2)
                else:
                    print(f"广告数量从 {last_ads_count} 减少到 {current_ads_count}")
                    time.sleep(1)
                
                last_ads_count = current_ads_count
            
            print("等待超时，继续执行...")
            return False
            
        except Exception as e:
            print(f"等待广告消失时出错: {e}")
            return False
    
    def login(self, username=None, password=None, auto_login_first=True):
        """
        登录主函数
        
        Args:
            username (str): 用户名
            password (str): 密码
            auto_login_first (bool): 是否先尝试自动登录
        """
        try:
            # 设置浏览器驱动
            if not self.setup_driver():
                return False
            
            # 先尝试自动登录
            if auto_login_first:
                if self.auto_login():
                    return True
            
            # 如果自动登录失败，尝试手动登录
            if username and password:
                return self.manual_login(username, password)
            else:
                print("请提供用户名和密码进行手动登录")
                return False
                
        except Exception as e:
            print(f"登录时出错: {e}")
            return False
    
    def logout(self):
        """登出"""
        try:
            if self.driver:
                # 查找登出按钮
                logout_selectors = [
                    "//a[contains(text(), '登出')]",
                    "//a[contains(text(), 'Logout')]",
                    "//button[contains(text(), '登出')]",
                    "//span[contains(text(), '登出')]"
                ]
                
                for selector in logout_selectors:
                    try:
                        elements = self.driver.find_elements(By.XPATH, selector)
                        if elements:
                            elements[0].click()
                            time.sleep(2)
                            break
                    except:
                        continue
                
                # 清除会话
                self.clear_session()
                self.is_logged_in = False
                print("已登出")
                
        except Exception as e:
            print(f"登出时出错: {e}")
    
    def get_driver(self):
        """获取浏览器驱动实例"""
        return self.driver
    
    def is_logged_in_status(self):
        """获取登录状态"""
        return self.is_logged_in
    
    def close(self):
        """关闭浏览器"""
        if self.driver:
            self.driver.quit()
            print("浏览器已关闭")

def main():
    """主函数 - 测试登录功能"""
    print("=" * 50)
    print("登录管理器测试")
    print("=" * 50)
    
    # 测试用的登录凭据
    username = "wangyukunop"
    password = "zxw123456"
    
    # 创建登录管理器实例
    login_manager = LoginManager(headless=False)
    
    try:
        # 尝试登录
        if login_manager.login(username=username, password=password):
            print("登录成功！")
            
            # 获取驱动实例供其他模块使用
            driver = login_manager.get_driver()
            print(f"驱动实例: {driver}")
            
            # 保持浏览器打开一段时间供查看
            input("按回车键继续...")
            
        else:
            print("登录失败")
            
    except KeyboardInterrupt:
        print("\n用户中断")
    except Exception as e:
        print(f"运行出错: {e}")
    finally:
        login_manager.close()

if __name__ == "__main__":
    main()